/* Copyright (C) 2007-2010 Open Information Security Foundation
 *
 * You can copy, redistribute or modify this Program under the terms of
 * the GNU General Public License version 2 as published by the Free
 * Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * version 2 along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301, USA.
 */

/**
 * \ingroup decode
 *
 * @{
 */


/**
 * \file
 *
 * \author Prabhakaran Kasinathan <kasinthan@ismb.it>
 *
 * Decode 6LoWPAN
 */

#include "suricata-common.h"
#include "decode.h"
#include "decode-sixlowpan.h"
#include "decode-events.h"

#include "util-unittest.h"
#include "util-debug.h"

void DecodeSixlowpan(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq)
{
    SCPerfCounterIncr(dtv->counter_sixlowpan, tv->sc_perf_pca);

SCLogInfo("Entered 6lowpan decoder *****\n");
/*  
  if (len < SIXLOWPAN_HEADER_LEN) {
        ENGINE_SET_EVENT(p,SIXLOWPAN_PKT_TOO_SMALL);
	//SCLogError(SC_ERR_UNIMPLEMENTED,"header length less event marked");
        return;
    }
*/
    p->sixlowh = (SixlowpanHdr *)pkt;
  
  printf("sixlowpan type %x | macro: \n %x",p->sixlowh->sixlowpan_type,SIXLOWPAN_GET_UCMPHEADER_TYPE(p));    
 
	if (SIXLOWPAN_GET_UCMPHEADER_TYPE(p) == 0x41) {
	
	printf("\n Going into IPV6 decoder :D");
	DecodeIPV6(tv, dtv, p, pkt + 1,
                       len - 1, pq);

	}
  /*  
     if (p->sixlowh == NULL)
	SCLogError(SC_ERR_UNIMPLEMENTED,"6LoWPAN packet is null");
        return;
*/
       
    uint8_t sixtype;	
    
   sixtype = (((p->sixlowh->sixlowpan_type) & 0xc0) >> 6); // should convert into a macro fn

	
  
    switch (sixtype) {
        case SIXLOWPAN_NLF:
             SCLogInfo("No Lowpan Frame **");
            
            break;
        case SIXLOWPAN_LIPADDH:	
            SCLogInfo("Lowpan IPv6 Address Header **");
            
            break;
        case SIXLOWPAN_LMESHH:
            SCLogInfo("Lowpan Mesh Header **");
            
            break;
        case SIXLOWPAN_LFRAGH:
	    SCLogInfo("Lowpan Frag Header **");
            SCLogInfo("\n Length  %d | 6lowpan Type: %x | datagram Size %d | Datagram Tag %04x",
		     len,(p->sixlowh->sixlowpan_type),(p->sixlowh->sixlowpan_datag_size),(p->sixlowh->sixlowpan_datagram_tag));    
            break;

	default:
            SCLogDebug("p %p pkt %p SixLoWPAN type %04x not supported", p,
                       pkt, ntohs(p->sixlowh->sixlowpan_type));
    }

    return;
}

#ifdef UNITTESTS
/** DecodeSixlowpantest01
 *  \brief Valid SixLoWPAN packet
 *  \retval 0 Expected test value
 */
static int DecodesixlowpanTest01 (void)   {

	/* yet to be written */
    /* ICMP packet wrapped in PPPOE */
    uint8_t raw_sixh[] = {
        0xe0, 0x8a, 0xa5, 0x20, 0x10, 0x90, 0x01, 0x90,
	0x01, 0x90, 0x01, 0x90, 0x01, 0x90, 0x01, 0xcd,
	0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
        0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
        0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
        0xab, 0xcd };

    Packet *p = SCMalloc(SIZE_OF_PACKET);
    if (p == NULL)
    return 0;
    ThreadVars tv;
    DecodeThreadVars dtv;

    memset(&dtv, 0, sizeof(DecodeThreadVars));
    memset(&tv,  0, sizeof(ThreadVars));
    memset(p, 0, SIZE_OF_PACKET);
    p->pkt = (uint8_t *)(p + 1);

    DecodeSixlowpan(&tv, &dtv, p, raw_sixh, sizeof(raw_sixh), NULL);

    SCFree(p);
    return 0;
}
#endif /* UNITTESTS */


/**
 * \brief Registers SixLoWPAN unit tests
 * \todo More SixLoWPAN tests
 */
void DecodesixlowpanRegisterTests(void) {
#ifdef UNITTESTS
    UtRegisterTest("DecodesixlowpanTest01", DecodesixlowpanTest01, 1);
#endif /* UNITTESTS */
}
/**
 * @}
 */

